import path from 'node:path'

import { listMigrations } from '../utils/listMigrations'
import { describeMatrix, sqliteOnly } from './__helpers__/conditionalTests'
import { createDefaultTestContext } from './__helpers__/context'

const ctx = createDefaultTestContext()

const itIf = (condition: boolean) => (condition ? it : it.skip)

describe('listMigrations', () => {
  describeMatrix(sqliteOnly, 'SQLite', () => {
    it('lists migrations without error if the directory does not exist', async () => {
      ctx.fixture('schema-only-sqlite')

      const migrationsDirectoryPath = path.join(ctx.fs.cwd(), 'prisma', 'migrations')
      const migrationsList = await listMigrations(migrationsDirectoryPath, '')

      expect(migrationsList).toMatchObject({
        baseDir: migrationsDirectoryPath,
        lockfile: {
          content: null,
          path: 'migration_lock.toml',
        },
        migrationDirectories: [],
      })
    })

    it('lists migrations with directory contents, if they are readable', async () => {
      ctx.fixture('edited-and-draft')

      const migrationsDirectoryPath = path.join(ctx.fs.cwd(), 'prisma', 'migrations')
      const migrationsList = await listMigrations(migrationsDirectoryPath, '')

      expect(migrationsList).toMatchObject({
        baseDir: migrationsDirectoryPath,
        lockfile: {
          content: expect.any(String),
          path: 'migration_lock.toml',
        },
        migrationDirectories: expect.any(Array),
      })

      expect(migrationsList.lockfile.content).toMatchInlineSnapshot(`
        "# Please do not edit this file manually
        provider = "sqlite""
      `)

      expect(migrationsList.migrationDirectories).toHaveLength(2)
      const [migration1, migration2] = migrationsList.migrationDirectories

      expect(migration1).toMatchObject({
        migrationFile: {
          content: {
            tag: 'ok',
            value: expect.any(String),
          },
          path: 'migration.sql',
        },
        path: '20201117144659_test',
      })

      expect(migration1.migrationFile.content.value).toMatchInlineSnapshot(`
        "-- CreateTable
        CREATE TABLE "Blog" (
            "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,


            "viewCount20" INTEGER NOT NULL
        );
        "
      `)

      expect(migration2).toMatchObject({
        migrationFile: {
          content: {
            tag: 'ok',
            value: expect.any(String),
          },
          path: 'migration.sql',
        },
        path: '20201117152717_draft',
      })

      expect(migration2.migrationFile.content.value).toMatchInlineSnapshot(`"-- This is an empty migration."`)
    })
  })

  itIf(process.platform !== 'win32')('gracefully handles non accessible files', async () => {
    ctx.fixture('schema-only-sqlite')

    const migrationsDirectoryPath = path.join(ctx.fs.cwd(), 'prisma', 'migrations')

    await ctx.fs.writeAsync(
      path.join(migrationsDirectoryPath, '20230101000000_non_readable', 'migration.sql'),
      '-- This is a non readable migration.',
      { mode: 0o111 },
    )

    await ctx.fs.writeAsync(
      path.join(migrationsDirectoryPath, '20230102000000_readable', 'migration.sql'),
      '-- This is an empty migration.',
    )

    const migrationsList = await listMigrations(migrationsDirectoryPath, '')

    expect(migrationsList).toMatchObject({
      baseDir: migrationsDirectoryPath,
      lockfile: {
        content: null,
        path: 'migration_lock.toml',
      },
      migrationDirectories: expect.any(Array),
    })

    expect(migrationsList.migrationDirectories).toHaveLength(2)
    const [migration1, migration2] = migrationsList.migrationDirectories

    expect(migration1).toMatchObject({
      migrationFile: {
        content: {
          tag: 'error',
          value: expect.stringMatching(/EACCES: permission denied/),
        },
        path: 'migration.sql',
      },
      path: '20230101000000_non_readable',
    })

    expect(migration1.migrationFile.content.value).toContain(
      path.join(migrationsDirectoryPath, '20230101000000_non_readable', 'migration.sql'),
    )

    expect(migration2).toMatchObject({
      migrationFile: {
        content: {
          tag: 'ok',
          value: expect.any(String),
        },
        path: 'migration.sql',
      },
      path: '20230102000000_readable',
    })

    expect(migration2.migrationFile.content.value).toMatchInlineSnapshot(`"-- This is an empty migration."`)
  })
})
